﻿using System;
using System.Collections.Generic;
using System.Linq;
using HenIT.Utilities;
using System.IO;

namespace EventScavenger
{
    class Program
    {
        static void Main(string[] args)
        {
            if (CommandLineUtils.IsCommand(args, "-?", "/?", "-h", "/h"))
            {
                ShowHelp();
            }
            else
            {
                string server = CommandLineUtils.GetCommand(args, ".", "-s:", "/s:", "-server:", "/server:");
                string database = CommandLineUtils.GetCommand(args, "EventScavenger", "-d:", "/d:", "-database:", "/database:");
                string outputFile = CommandLineUtils.GetCommand(args, "", "-o:", "/o:", "-output:", "/output:");
                string logsFilters = CommandLineUtils.GetCommand(args, "", "-log:", "/log:");
                string sourceFilters = CommandLineUtils.GetCommand(args, "", "-source:", "/source:");
                string eventIdFilters = CommandLineUtils.GetCommand(args, "", "-eventid:", "/eventid:");
                string typeFilters = CommandLineUtils.GetCommand(args, "", "-type:", "/type:");
                string fromDateStr = CommandLineUtils.GetCommand(args, "", "-f:", "/f:", "-from:", "/from:");
                string untilDateStr = CommandLineUtils.GetCommand(args, "", "-u:", "/u:", "-until:", "/until:");
                string lastMinutesStr = CommandLineUtils.GetCommand(args, "", "-last:", "/last:");
                string topStr = CommandLineUtils.GetCommand(args, "1000", "-top:", "/top:");
                string messageFilter = CommandLineUtils.GetCommand(args, "", "-message:", "/message:");
                string queryFile = CommandLineUtils.GetCommand(args, "", "-q:", "/q:", "-queryfile:", "/queryfile:");

                int tmp;
                int topCount = 1000;
                int lastMinutes = 0;
                string[] logsFilterArray = new string[] { };
                string[] sourceFilterArray = new string[] { };
                int[] eventIDArray = new int[] { };
                DateTime fromDate = new DateTime(2000, 1, 1);
                DateTime untilDate = DateTime.Now;
                if (topStr.Length > 0 && !int.TryParse(topStr, out topCount))
                {
                    Console.WriteLine("Invalid top count specified! The value must be an integer.");
                }
                else if (fromDateStr.Length > 0 && !DateTime.TryParse(fromDateStr, out fromDate))
                {
                    Console.WriteLine("Invalid from date/time specified! Value must be a valid date.");
                }
                else if (untilDateStr.Length > 0 && !DateTime.TryParse(untilDateStr, out untilDate))
                {
                    Console.WriteLine("Invalid until date/time specified! Value must be a valid date.");
                }
                else if (lastMinutesStr.Length > 0 && !int.TryParse(lastMinutesStr, out lastMinutes))
                {
                    Console.WriteLine("Invalid last X minutes specified! The value must be an integer.");
                }
                else if (eventIdFilters.Length > 0 && (from s in eventIdFilters.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
                                                       where !int.TryParse(s, out tmp)
                                                       select s).Count() > 0)
                {
                    Console.WriteLine("Invalid event IDs specified! The values must be integers.");
                }
                else
                {
                    if (logsFilters.Length > 0)
                        logsFilterArray = logsFilters.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                    if (sourceFilters.Length > 0)
                        sourceFilterArray = sourceFilters.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                    if (eventIdFilters.Length > 0)
                        eventIDArray = (from s in eventIdFilters.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
                                        select int.Parse(s)).ToArray();
                    if (fromDateStr.Length == 0 && lastMinutes > 0)
                    {
                        fromDate = untilDate.AddMinutes(-lastMinutes);
                    }

                    EventScavengerDAL eventScavengerDAL = new EventScavengerDAL();
                    eventScavengerDAL.Server = server;
                    eventScavengerDAL.Database = database;
                    eventScavengerDAL.SetConnection();

                    eventScavengerDAL.MaxCount = topCount;
                    eventScavengerDAL.FromDate = fromDate;
                    eventScavengerDAL.UntilDate = untilDate;
                    eventScavengerDAL.EventLogEntryType = GetEventLogEntryTypes(typeFilters);
                    eventScavengerDAL.ViewDisabledMachineLogs = true;
                    eventScavengerDAL.MachineLogFilters = GetMachineLogFilters(logsFilterArray);
                    eventScavengerDAL.ShowAllMachineLogs = logsFilterArray.Length == 0;
                    eventScavengerDAL.EventIdsVisible = GetEventIdFilters(eventIDArray);
                    eventScavengerDAL.ViewAllEventIDs = eventIDArray.Length == 0;
                    eventScavengerDAL.SourceFilters = GetSourceFilters(sourceFilterArray);
                    eventScavengerDAL.ShowAllSources = sourceFilterArray.Length == 0;
                    eventScavengerDAL.MessageFilter = messageFilter;

                    List<EventEntry> entries = eventScavengerDAL.GetEntries();
                    OutputEntries(outputFile, entries);

                }
            }
            Console.WriteLine("Done");
#if DEBUG
            Console.ReadKey();
#endif
        }

        #region Outputting results
        private static void OutputEntries(string outputFile, List<EventEntry> entries)
        {
            string outputFormat = "{0},{1},{3},{4},{5},{6}";

            TextWriter outputStream;
            try
            {
                if (outputFile.Length == 0)
                {
                    outputStream = Console.Out;
                }
                else
                {
                    outputStream = File.CreateText(outputFile);
                }

                foreach (EventEntry entry in entries)
                {
                    outputStream.WriteLine(outputFormat,
                        entry.MachineName,
                        entry.LogName,
                        entry.EventTypeName,
                        entry.TimeGenerated,
                        entry.SourceName,
                        entry.EventID,
                        entry.Message.Replace(',', ' ').Replace('\r', '-').Replace('\n', '>'));
                }
                outputStream.Flush();
                outputStream.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        } 
        #endregion

        #region Query data format helpers
        private static List<string> GetSourceFilters(string[] sourceFilterArray)
        {
            return (from s in sourceFilterArray
                    orderby s
                    select s).ToList();
        }
        private static List<int> GetEventIdFilters(int[] eventIDArray)
        {
            return (from int i in eventIDArray
                    orderby i
                    select i).ToList();
        }
        private static List<MachineLogEntry> GetMachineLogFilters(string[] logsFilterArray)
        {
            List<MachineLogEntry> list = new List<MachineLogEntry>();
            foreach (string log in logsFilterArray)
            {
                if (log.Contains('\\'))
                {
                    MachineLogEntry mle = new MachineLogEntry(log.Split('\\')[0], log.Split('\\')[1]);
                    list.Add(mle);
                }
            }
            return list;
        }
        private static EventLogEntryTypes GetEventLogEntryTypes(string typeFilters)
        {
            if (typeFilters.Length == 0)
                return EventLogEntryTypes.All;
            else if (typeFilters.Length == 1)
            {
                switch (typeFilters.ToUpper())
                {
                    case "E":
                        return EventLogEntryTypes.Errors;
                    case "W":
                        return EventLogEntryTypes.Warnings;
                    case "I":
                        return EventLogEntryTypes.Information;
                    default:
                        return EventLogEntryTypes.All;
                }
            }
            else
            {
                return EventLogEntryTypes.ErrorsAndWarnings;
            }
        } 
        #endregion

        private static void ShowHelp()
        {
            Console.WriteLine("Usage: ELSQueryCMD.exe [-s:server] [d:database] [-o:outputFile] [Filters]");
            Console.WriteLine("  Filters:");
            Console.WriteLine("    [-log:machineLog1[,machineLog]]");
            Console.WriteLine("    [-source:eventSource1[,eventSource2]]");
            Console.WriteLine("    [-eventid:eventid1[,eventid2]]");
            Console.WriteLine("    [-type:type1,[type2]] - possible values 'I', 'W', 'E' or 'EW'");
            Console.WriteLine("    [-f:fromDateTime]");
            Console.WriteLine("    [-u:untilDateTime] - default to current date/time");
            Console.WriteLine("    [-last:lastXMinutes] - time span in minutes");
            Console.WriteLine("    [-top:topCount] - default 1000");
            Console.WriteLine("    [-message:messageContains]");
            Console.WriteLine("   Note: Remember to add double quotes for values containing spaces"); 
            Console.WriteLine(" Explanation");
            Console.WriteLine("   server - SQL server containing EventScavenger database - default '.'");
            Console.WriteLine("   database - EventScavenger database name - default 'EventScavenger'");
            Console.WriteLine("   outputFile - write output to file (csv format)");
            Console.WriteLine(" Examples");
            Console.WriteLine("   ELSQueryCMD.exe -s:serverX \"-o:c:\\my events\\events.txt\"");
            Console.WriteLine("   ELSQueryCMD.exe -s:serverX -log:serverY\\Application -type:E,W -top:500");
            Console.WriteLine("   ELSQueryCMD.exe \"-f:2010-11-1 10:00\" \"-u:2010-11-1 11:00\"");
            Console.WriteLine("   ELSQueryCMD.exe \"-u:2010-11-1\" -last:2880");
            Console.WriteLine("   ELSQueryCMD.exe -eventid:1,2,3 \"-source:Service Control Manager\"");
        }
    }
}
